ci: replace yarn 1.x with bun for dev tooling - #8386
Conversation
🎉 All green!🧪 All tests passed 🔄 Datadog retried 1 test - 1 passed on retry 🔄 Datadog auto-retried 2 jobs - 1 passed on retry 🎯 Code Coverage (details) 🔗 Commit SHA: 46d6e48 | Docs | View more details | Give us feedback! |
Overall package sizeSelf size: 8.03 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.3.3 | 125.43 kB | 441.72 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | dc-polyfill | 0.1.11 | 25.74 kB | 25.74 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
BenchmarksBenchmark execution time: 2026-08-18 16:20:47 Comparing candidate commit 46d6e48 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 2286 metrics, 6 unstable metrics.
|
This reverts commit 6e415ed plus its follow-up workarounds. Two 1.3.13 regressions surfaced once that bump rolled through CI: 1. `bun add <tarball>` of a wide tree (`/tmp/dd-trace.tgz`, ~31 transitives) stalls forever on the github-hosted runner image. `Resolving dependencies` prints once, then no progress, and the runner kills the job at the 6-hour cap. Same shape as oven-sh/bun#29525 — the resolver queues every package-manifest request up front and the runner network swallows them. 2. `bun install --linker=isolated` lands different transitive versions for `@langchain/openai@0.0.34/@langchain/core` depending on host OS: `0.2.36` on macOS, `0.1.63` on Linux runners. The langchain regression spec sends a `{role, content}` JSON message that only `0.2.x`'s `coerceMessageLikeToMessage` accepts; under `0.1.x` it throws `TypeError: messageLike is not iterable` and fails the chat-model test even though the local dev loop is green. Bun does not support nested or scoped overrides (oven-sh/bun#1134), so there is no per-consumer knob. Going back to `1.3.1` everywhere — the version master uses today — clears both. The `lockfileVersion` is stable across the two bun releases, so the repository lockfile downgrade is purely the `bun@<ver>` self-pin and the matching `@oven/bun-*` platform binaries. Drop this commit (and re-bump) once a bun release fixes the regressions. This also drops: - the matrix-specific `bun 1.3.1` pin in `package-manager (bun)`, - the `gai.conf` IPv4-first workaround in the same job, - the no-op `@langchain/openai@0.0.34/@langchain/core` override that bun silently ignored anyway. PR-URL: #8386
a637e6c to
419719e
Compare
c11d82c to
dd61b26
Compare
The LLMObs spec anchored `openai` at `versions/node_modules/@openai/agents-openai`, a hoisted path bun's isolated linker never creates, so the suite failed at its `before` hook with `Cannot find module 'openai'`. Resolving from the loaded `@openai/agents-openai` build pins the copy that build itself uses, the same way the APM plugin setup now does.
Five `>> $GITHUB_OUTPUT` redirects in this workflow were left unquoted, which shellcheck flags as SC2086 and which master already cleared everywhere else ahead of enabling the rule.
1. Keep the version bump at HEAD on release proposal branches by preventing license auto-commits there. 2. Keep scoped package identities slash-delimited so Windows sandbox setup patches their peers. 3. Regenerate license attribution when any source input changes instead of only on lock updates.
…range `@aws-sdk/client-bedrock-runtime` forced `@smithy/node-http-handler` at `*`, so every bedrock sandbox received the newest published handler regardless of the `@smithy/*` generation it was built against. The 3.422.0 sandbox declares `^2.1.5`, got a v4 handler, and that handler resolved its own `@smithy/core` v3 independently of the rest of the sandbox, so loading it threw `MODULE_NOT_FOUND` on `@smithy/core/protocols`. Which majors collide depends on what the registry published inside the install's `minimumReleaseAge` window, so the sandbox broke on a day when nothing in the repository had changed. A forced transitive now takes an explicit `version` first, then the range the installed package declares for itself, and only then the latest-version pin. Entries genuinely absent from their parent's manifest (`moleculer` → `bluebird`, `@prisma/client` → `mongodb`) are unaffected. The sandbox assertion accepted any `semver.validRange`, which `*` satisfies, and now requires the injected range to be a subset of what the client itself declares.
Bun sets `npm_execpath` to its own executable rather than to a JavaScript entry point, so the bootstrap ran `node <60 MB binary> install` and Node exited on a bare `SyntaxError` while parsing it as CommonJS. The version check that reports `Could not install Bun` never ran, leaving a parser error as the only output. The branch is reached whenever the bootstrapped binary is missing, which is what `bun install --ignore-scripts` leaves behind, so any Bun-launched script in that state failed with an unrelated error.
Each vendored bundle contains code from several packages, but the plugin emitted `modules[0].licenseText` — whichever package the bundler happened to order first. That order follows the installer's `node_modules` layout, so replacing Yarn with Bun reshuffled it and `@apm-js-collab/code-transformer` shipped Mozilla's BSD-3-Clause text in place of its own Apache-2.0 license, while every other package in the bundle went unattributed. Each `LICENSE` now carries every bundled package's text, name-sorted so the result no longer depends on the installer. A package that publishes no license file falls back to a canonical template chosen by the SPDX id its manifest declares, which is how `crypto-randomuuid` resolves, and an id with no template fails the build instead of shipping a bundle with a missing license.
1. The lock walk followed only `dependencies` and `optionalDependencies`, so a production package's peers were treated as dev-only and went unattributed. `@datadog/openfeature-node-server` is an optional dependency whose peer `@openfeature/server-sdk` is satisfied by a range declared under `devDependencies`; `bun install --production` resolves it, so it and `@openfeature/core` ship inside the OCI package with no license row. A peer nobody installed has no lock entry and still drops out. 2. The generated CSV had moved to LF while `.github/vendored-dependencies.csv` stayed CRLF. The license workflow appends the second file to the first, so the result carried mixed endings, editors re-LF it on save, and the release tooling re-committed it on every run.
`bun audit --ignore <id>` accepts ids it never saw without complaining, so an inline ignore list keeps suppressing an advisory long after the dependency was patched and nothing reports that the entry is dead. Three of the five ignored advisories were in that state: `form-data`, `path-to-regexp`, and `undici` each had a patched release inside the range their parents already declare, so re-resolving those three lock entries clears them and the ignores go away. Accepted advisories now live in `.github/audit-allowlist.json`, one entry per directory with a written reason, and the wrapper fails both on an advisory that is not accepted and on an acceptance that no longer matches anything. The threshold is per directory because `vendor` is bundled and shipped, so a moderate advisory there reaches customers, while `--audit-level=high` had been filtering it out.
The cassette reference told readers to run `PLUGINS=<integration> yarn services` to install a missing version fixture. Yarn is no longer installed, so the command fails outright; the fixture stays missing and the spec keeps reporting a broken module. The guard test that keeps yarn out of the tree fails on the reference too.
…list The generator fed `.github/vendored-dependencies.csv` through the same map as the lockfile walk, so its rows were sorted in among the installed packages. Those two rows attribute code copied into this repo — a regex from `is-git-url`, handler-path logic from the AWS Lambda runtime interface client — not packages the artifact resolves. Alphabetical placement asserts we ship an `is-git-url` that no lockfile has ever contained, which is the opposite of what an attribution file is read for. They now trail the sorted dependencies, the layout `dd-license-attribution` produced by appending the file. A name appearing in both lists would emit two rows for one component, and `check_licenses.js` compares name sets, so nothing downstream would catch it. The generator now fails instead.
Severity is ranked by index into a fixed list, and an unrecognized string yields -1, which sorts below every configured threshold. A renamed or newly added bun severity therefore skips every advisory carrying it and the job reports a clean tree, which is the failure the wrapper exists to prevent rather than one it can absorb quietly.
The workflow only watched lockfiles, so a PR could add or edit an entry in `.github/audit-allowlist.json` — or change `scripts/audit.js` itself — and merge without ever running the wrapper that checks every exemption still carries a reason and is still reported. An exemption is only as good as the run that re-checks it, so the policy and the enforcing script now trigger the workflow alongside the lockfiles they gate. Refs: #8386
The setup action hard-coded `bun@1.3.14` while `package.json` holds the pin that `scripts/bun.js` enforces. Dependabot updates the devDependency without touching the action, and nothing then runs the wrong Bun — `getBunBinary()` bootstraps the pinned one locally — but every CI job pays for that bootstrap until someone notices the two numbers drifted. Read the pin instead of restating it. The spec assertion moves with it: it used to compare the two literals, and now requires the action to carry no literal at all. The playwright Dockerfile pin stays literal because its `FROM` line needs the image digest too. Refs: #8386
The langchain entry pinned `@langchain/openai@0.0.34`'s copy of `@langchain/core` through a Yarn-style selective key (`@langchain/openai@0.0.34/@langchain/core`). Bun only honours a bare package name: it copies the key into the manifest and never applies it. Verified against the pinned Bun — a selective key leaves `@langchain/core` at 0.2.36 while an equivalent top-level override moves it — so the line read as an enforced pin while resolution was untouched, and the old spec asserted the dead key was present rather than that it did anything. 1. Remove the override. 0.0.34's own declared range already lands inside `^0.2.0`, which is what the spec now asserts. A top-level override is not the fix: it is workspace-wide and would drag langgraph's `>=1.1.16` sandboxes down to the 0.2 line. 2. Reject any override key that is not a bare package name at generation time, so the next selective or nested override fails loudly instead of reading as enforced. Refs: #8386
Mergegate failed with "CODEOWNERS missing" for `.github/audit-allowlist.json`, the fourth such failure on this branch after `docs/bun.lock`, `versions/bunfig.toml` and `vendor/bun.lock`. The main lint does run a codeowners audit, but only over five globs — `**/*.spec.js`, `benchmark/sirun/**`, `.agents/**`, `.claude/**` and `integration-tests/**` — so no local gate covered the tree this branch keeps adding files to, and every gap had to be found by pushing. 1. Default the whole `/.github/` tree to the platform team instead of listing `/.github/actions/` and `/.github/all-green/` one directory at a time. GitHub applies the last matching rule, so the per-product entries further down keep the workflows and directories they already claim. This closes 16 pre-existing gaps, among them the issue templates, `dependabot.yml`, and the audit, flakiness, platform and release-proposal workflows. 2. Add `.github/**` and `scripts/**` to `lint:codeowners:ci`, so the next unowned file fails locally instead of in mergegate. Drive-by: move the `/docs/bun.lock` and `/vendor/bun.lock` rules out of the middle of the workflow block, where they had nothing to do with their neighbours, into the Language Platform section. Ownership is unchanged; no other rule matches either path. Refs: #8386
## Summary - keep sparse CI and OCI installs complete - restore fail-closed Bun lock traversal and exact attribution refresh - remove redundant fallback branches exposed by current lint ## Why Sparse jobs invoke the Node setup action, which reads package.json to select the pinned Bun version. The OCI build also needs trusted dependency lifecycle scripts while skipping only the package prepare hook. The extracted lock reader had lost the previous parser validation and ancestor/workspace resolution, allowing malformed or incomplete locks to silently shrink license attribution. Single-version rows also retained stale registry metadata. ## Test plan - npm run test:scripts - npm run lint - node scripts/generate-3rdparty-licenses.js --check - changed-line c8 coverage for the affected scripts
## Summary Refresh the root Bun lock after the eslint-plugin-unicorn bump. Classify Bun locks correctly in release changelogs. Narrow GitHub ownership and remove the obsolete consumer-install action. ## Why The rebased tree failed every frozen install because master advanced a dependency without the PR's new lockfile. Master's release tooling also reintroduced Yarn-only assumptions, while recursive GitHub ownership claimed workflows that already have product owners. ## Test plan Complete script suite, full repository lint, frozen Bun install, changed-line coverage, generated license check, and shell syntax checks.
## Summary Fresh license regeneration and dependency audits now pass against the Bun lockfiles. ## Why The license workflow invoked the Bun lock parser without installing jsonc-parser. New high-severity advisories also made the root and docs audits reject stale lock resolutions. ## Test plan - `bun install --frozen-lockfile --ignore-scripts` in root and docs - `node scripts/audit.js . docs` - `node scripts/generate-3rdparty-licenses.js` - `npm run test:scripts` - `npm run lint` PR-URL: #8386
## Summary Exact plugin pins and reviewed copyright attribution remain authoritative; audit and package-size jobs use current Bun behavior. ## Why Flexible latest ranges let plugin sandboxes drift above the tested pin, registry author fields overwrite reviewed copyright, and stale workarounds obscure Bun 1.3.14 behavior. Dependabot now supports bun.lock, so a scheduled wrapper duplicates upstream advisory monitoring. ## Test plan - npm run test:scripts - ./node_modules/.bin/mocha scripts/test/generate-3rdparty-licenses.spec.js packages/dd-trace/test/plugins/versions.spec.js - PLUGINS=pino npm run test:plugins - npm run lint - actionlint .github/workflows/audit.yml .github/workflows/instrumentation.yml .github/workflows/project.yml - coverage-diff.js HEAD
Dependabot supports Bun version updates but not security updates, so newly disclosed advisories do not change bun.lock or trigger a pull-request audit.
* test(plugins): remove obsolete Bun dependency workarounds Bun 1.3.14 and the current isolated installer produce valid dependency graphs for these packages without the added direct dependencies and overrides. * test(plugins): remove stale workaround assertions `test:scripts` still asserted Knex, Limitd, and AI dependency accommodations after those configurations were removed, so the release-scripts job failed.
A second Bun invocation is unsafe when the generated workspace state from the first failure remains in place.\n\nAllow one second workflow attempt for transient runner failures, and start both from an empty root node_modules tree.
1. @vscode/sqlite3 can run before its package-local tar dependency is available under Bun isolated workspaces. 2. The Yarn-free test PATH also hid Node, so trusted dependencies with Node lifecycle scripts failed before assertions ran.
@confluentinc/kafka-javascript@1.10.0 has no Node 26 prebuild, and its fallback source build fails before instrumentation tests start. The shared action stays on Node latest by default while this job uses the newest runtime its plugin matrix supports.
Master updated @datadog/pprof without the Bun lock, so every frozen CI install rejected the rebased dependency tree.
The Confluent 1.0-1.3 line has no Node 24 prebuild, so the upper-runtime install falls back to a broken source build. Use the plugin matrix's existing Node 24 package floor while Node 18 retains >=1.0 coverage.
Dependabot does not create security PRs for Bun locks, so its PR audit is additive to the existing scheduled, manual, and path-triggered audit. Checked advisory acceptances now fail when their justification goes stale instead of silently suppressing a later reintroduction. Source-archive prepare can run before dev dependencies exist, and isolated Bun installs hardlink cache files. Resolving the pinned binary and replacing patched files by inode prevents bootstrap failures and shared-cache mutation.
Bun defaults to 48 concurrent network requests, which caused unrelated plugin jobs to fail while extracting registry tarballs before tests started. Apply the established eight-request limit here and keep the reviewed single-attempt behavior.
Concurrent generated-workspace downloads intermittently hit Bun tarball extraction failures, so unrelated plugin jobs stop before tests.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 46d6e48a33
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| We use [bun](https://bun.com/) (1.3.14, matching `devDependencies.bun` in `package.json`) for installing | ||
| dependencies and the per-plugin sandbox installs. Run-scripts (`test:*`, `lint`, …) go through | ||
| `npm`. The easiest way to install bun: |
There was a problem hiding this comment.
Migrate the no-sandbox link path off Yarn
When a contributor enables TESTING_NO_INTEGRATION_SANDBOX, integration-tests/helpers/index.js:568-575 still invokes yarn link twice. The revised setup now asks contributors to install only Bun and use npm for scripts, so a clean environment following these instructions fails with yarn: not found before running the integration tests. Convert that branch to npm link (as the esbuild fixture now does) or retain Yarn as a documented prerequisite.
AGENTS.md reference: AGENTS.md:L11-L16
Useful? React with 👍 / 👎.
Summary
Replace Yarn 1.x across repository dev tooling with Bun 1.3.1 for installs and npm for run-scripts. Root and docs installs are lockfile-frozen. Per-plugin sandboxes retain isolated dependency trees and cached highest-in-range resolution. Yarn remains only where tests deliberately exercise it as a user package manager.
Fresh npm releases are held for three days by both root and sandbox installs. Temporary integration and package-manager sandboxes explicitly load the tracked Bun config. All Green installs its GitHub clients from a dedicated frozen lock before minting STS credentials. License attribution reads exact versions from Bun and npm locks, combines metadata across multiple installed versions, and fails closed on registry or license gaps.
Why
Yarn Classic cannot enforce a minimum publication age on new resolutions. Bun gives us the age gate and faster installs. Frozen locks cover repeat installs, while the age gate covers dynamic sandbox resolution. Bun is pinned to 1.3.1 because later tested releases can stall during dependency resolution in this repository.
The local Bun-lock license reader is a stop gap until
watson/dd-license-attributionsupportsbun.lock. Once released there, replace it with the upstream command and remove the local parser.